# -*- coding: UTF-8 -*-
from selenium.webdriver import Edge
import json5 as json
import time


class ElementException(Exception):
    def __init__(self, elementName:str):
        self.elementName = elementName
    def __str__(self) -> str:
        return f"{self.elementName} Were Wrong"

class WrongPasswordException(Exception):
    def __init__(self, userName:str):
        self.userName = userName
    def __str__(self) -> str:
        return f"{self.userName}: Password Wrong"

class NotInTimeException(Exception):
    def __str__(self) -> str:
        return f"Time Up Today"

def TryUntilTimeOut(func, time_out:int=10):
    """循环尝试, 直到超时返回的函数"""
    start_time = time.time()
    now_time = time.time()
    flag = BaseException
    while True:
        now_time = time.time()
        if (now_time - start_time) > time_out:
            return flag
        try:
            flag = func()
            return flag

        except BaseException as e:
            flag = e
            print("自动重试", e)

def TryEveryElement(func, Elements:list, tryAll=False):
    """尝试将列表中的所有元素输入执行"""
    returns = []
    ifSuccess = False
    for i in Elements:
        try:
            func(i)
            returns.append([i, True])
            ifSuccess = True
            if not tryAll:
                return returns
        except BaseException as e:
            print(i, str(e))
            returns.append([i, False])
    if not ifSuccess:
        raise BaseException()
    return ifSuccess, returns

def TryGetFromEveryElement(func, Elements:list):
    """尝试将列表中的所有元素输入执行"""
    result = BaseException()
    for i in Elements:
        try:
            result = func(i)
            break
        except BaseException as e:
            result = e
    if isinstance(result, BaseException):
        raise result
    return result

class XMU_Reporter:
    def __init__(self, elements_json_path:str, driver:str) -> None:
        self.br = Edge(executable_path=driver)
        with open(elements_json_path,"r",encoding="utf-8") as f:
            JSON_string = f.read()
            self.elements = json.loads(JSON_string)
    
    def element_clicker(self, ElementKey:str):
        print(f"Clicking {ElementKey}")
        func = lambda x: self.br.find_element_by_xpath(x).click()
        func_try  = lambda : TryGetFromEveryElement(func, self.elements[ElementKey])
        result = TryUntilTimeOut(func_try)
        if isinstance(result, BaseException):
            raise ElementException(ElementKey)
        else:
            return result            
    
    def element_inputer(self, ElementKey:str, InputMessage:str):
        func_base = lambda x: self.br.find_element_by_xpath(x).send_keys(InputMessage)
        func_try  = lambda : TryEveryElement(func_base, self.elements[ElementKey])
        result = TryUntilTimeOut(func_try)
        if isinstance(result, BaseException):
            raise ElementException(ElementKey)
        else:
            return result            
    
    def get_element_attribute(self, ElementKey:str, attributeName:str):
        print(f"getting Attr {ElementKey}")
        func = lambda x: self.br.find_element_by_xpath(x).get_attribute(attributeName)
        func_try = lambda : TryGetFromEveryElement(func, self.elements[ElementKey])
        result = TryUntilTimeOut(func_try)
        if isinstance(result, BaseException):
            raise ElementException(ElementKey)
        else:
            return result
    
    def accept_alert(self):
        self.br.switch_to.alert.accept()
    

    def url_check(self, target_url:str):
        if self.br.current_url == target_url:
            return True
        else:
            raise BaseException()

    def page_auto_fresh_retry(self, func, max_refresh_num=5):
        result = BaseException
        for _ in range(max_refresh_num):
            try: 
                result = func()
                break
            except BaseException as e:
                self.br.refresh()
                result = e
        return result

    def login_page(self, username:str, password:str):
        self.br.get('https://xmuxg.xmu.edu.cn/app/214')
        time.sleep(0.5)
        self.element_clicker("Login_Way")
        print(username)
        self.element_inputer("Username_Input", username)
        print(password)
        self.element_inputer("Password_Input", password)
        
        self.element_inputer("Password_Input",  u'\ue007')
        func = lambda: self.url_check("https://xmuxg.xmu.edu.cn/platform")
        if isinstance(TryUntilTimeOut(func), BaseException):
            raise WrongPasswordException(username)
        return True
    
    def report_page(self):
        result = None
        self.br.get('https://xmuxg.xmu.edu.cn/app/214')  # 打卡界面
        self.element_clicker("My_Biao_Dan")
        if self.get_element_attribute("Time_disable", 'disabled') == "true":
            raise NotInTimeException()
        result = "Report Again"
        if self.get_element_attribute("Report_status", 'title') != "是 Yes":
            self.element_clicker("Select_Button")
            self.element_clicker("Yes_Option")
            result = "Report First Time"
        self.element_clicker("Save_Button")
        time.sleep(0.5)
        self.accept_alert()
        return result


    def main(self, username:str, password:str) -> str:
        result = self.page_auto_fresh_retry(lambda: self.login_page(username, password))
        if isinstance(result, BaseException):
            return str(result)
        result = self.page_auto_fresh_retry(self.report_page)
        return str(result)


if __name__ == "__main__":
    reporter = XMU_Reporter("E_dict.json", '.\\Drivers\\EDGE_100.0.1185.29.exe')
    try:
        with open("usernsme.json", 'r') as js_file:
            user_msg = json.load(js_file)
    except:
        with open("username.json", 'w') as js_file:
            username = input("User Name: ")
            password = input("Password : ")
            user_msg = [username, password, ""]
            js_string = json.dumps(user_msg, sort_keys=True, indent=4, separators=(',', ': '))
            js_file.write(js_string)
    print(reporter.main(username, password))
